﻿using System;
using System.Runtime.InteropServices;

namespace Blink1
{
	public class Blink1
	{
		/// <summary>
		/// Library for communicating with blink(1) USB RGB LEDs.
		/// On instantiation, enumerates the USB and records any plugged in blink(1) devices. 
		/// </summary>
		public Blink1()
		{
			Enumerate();
		}

		/// <summary>
		/// Open blink(1) device for use.  If multiple blink(1)s, opens the first device.
		/// </summary>
		/// <returns>true if device was opened, false if no device available.</returns>
		public Boolean Open()
		{
			_dev = blink1_open();
			return true;
		}

		/// <summary>
		/// Open a particular blink(1) device, if there are several
		/// </summary>
		/// <param name="i">integer id (0,1,2...) of device to open</param>
		/// <returns>true if device was opened, false otherwise</returns>
		public Boolean OpenById(int i)
		{
			_dev = blink1_openById(i);
			return true;
		}

		/// <summary>
		/// Close an open blink(1) device.
		/// </summary>
		public void Close()
		{
			blink1_close(_dev);
		}

		/// <summary>
		/// Set blink(1) to RGB color immediately.
		/// </summary>
		/// <param name="r">red component</param>
		/// <param name="g">green component</param>
		/// <param name="b">blue component</param>
		public void SetRgb(int r, int g, int b)
		{
			blink1_setRGB(_dev, r, g, b);
		}

		/// <summary>
		/// Fade to an RGB color over a period of milliseconds.
		/// </summary>
		/// <param name="millis">milliseconds fade time</param>
		/// <param name="r">red component</param>
		/// <param name="g">green component</param>
		/// <param name="b">blue component</param>
		public void FadeToRgb(int millis, int r, int g, int b)
		{
			blink1_fadeToRGB(_dev, millis, r, g, b);
		}

		/// <summary>
		/// FIXME: make more like Blink1.m enumerate
		/// </summary>
		/// <returns></returns>
		public int Enumerate()
		{
			return blink1_enumerate();
		}

		public static string GetCachedSerial(int i)
		{
			var wcstr = blink1_getCachedSerial(i);
			var result = Marshal.PtrToStringAuto(wcstr);
			return result;
		}

		// see: http://msdn.microsoft.com/en-us/magazine/cc164123.aspx#S7
		// and: http://msdn.microsoft.com/en-us/library/aa446532.aspx
		// and: http://www.codeguru.com/csharp/csharp/cs_data/article.php/c4217/Calling-Unmanaged-Code-Part-1--simple-DLLImport.htm

		private const string DllName = "blink1-lib.dll";
		private IntPtr _dev;

		[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
		public static extern IntPtr blink1_open();

		[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
		public static extern IntPtr blink1_openById(int i);

		[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
		public static extern void blink1_close(IntPtr dev);

		[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
		public static extern IntPtr blink1_setRGB(IntPtr dev, int r, int g, int b);

		[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
		public static extern IntPtr blink1_fadeToRGB(IntPtr dev, int millis, int r, int g, int b);

		[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
		public static extern int blink1_enumerate();

		[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
		public static extern IntPtr blink1_getCachedSerial(int i);

	}
}